前几天和东盟君讨论关于在 @property(nonatomic,copy)NSString * string;中 copy的使用问题. 虽然自己很明白,见到NSString,果断用 copy,但是却说不出个道道.
今天偶尔在一片国外论坛的文章上看到了关于这个的内容(因为在pad上看的,具体地址没法引用了).所以简单记录一下.
因为类似 NSString这样的不可变父类,它们有可变的子类(比如 NSMutableString),那么就可能造成修改指针指向的结果,而这是我们不愿意看到的
是比较抽象的描述,要弄明白这段话,需要明确 copy 做了什么 ?
在官方的描述中: copy是复制一个对象,并强引用它.
那么开始解释一开始的话:
假设我有一个 Person 类,他有一个 name属性,它是NSString类型的.不可变对象对吧.
那么问题来了,下面的语法是成立的:
1 | NSMutableString * mutableString = [[NSMutableString alloc]initWithString:@"gg"]; |
上面1处首先语法没有问题, NSString是 NSMutableString的父类.
然后这个时候,如果 name属性是 @property 是 strong的,
那么 per.name 和 mutableString 指向的是同一块内存区域,
那么,我就可以通过修改 mutableString来修改per.name了,而当初我们既然选择了 NSString,那么就是考虑到不会对其进行修改的.所以,这样违背了我们的初衷.
如果是copy,per.name在使用前会复制一份出来,这样使用的其实是它的副本,即使修改了mutableString也不会对per.name的本尊造成影响.
关于 copy 和 mutableCopy
现在我说的这两者是在代码中使用的时候,就是对象创建和赋值时候的.
苹果的设计是:
- copy 拿到的永远是不可变对象
- mutableCopy 拿到的是可变对象
为什么这样设计呢?
以上两者的调用者可能是 可变的或者不可变的,那么就会有四种组合,对于开发者去记忆四种组合是比较蹩脚的.所以干脆
- 不管调用者类型是可变与否,copy到得就不可变
- 不管调用者类型是可变与否,mutableCopy到得就是可变对象
关于创建可变类型
以前都是用类似 NSMutableString * string = [ NSMutableString string ];这样的方式创建,但是在和东盟君讨论的时候,打印了一下,发现 string的class是:
1 | NSString * string = [NSString stringWithFormat:@"string"]; |
打印结果:
1 | 2015-05-20 10:36:43.549 TestNsstring[10993:1874316] string is __NSCFString |
究其原因, NSString是一个类簇,具体的实现都会找到合适的类,这个不用纠结了.
不久之后,在 iOS6 by Tutorial中一书中看到关于 [@[] mutableCopy] 和 [@{} mutableCopy] 这样的用法.
也符合 copy 和 mutableCopy 的准则